#include "Machine.h"
#include <math.h>

namespace SimpleC
{
	typedef void (*ExternFunction)(BufferRef<unsigned char> args, WritableBuffer & retVal);

	class SystemFunctionHandler : public ExternFunctionHandler
	{
	private:
		Dictionary<String, ExternFunction> externFuncs;
		static void sin(BufferRef<unsigned char> args, WritableBuffer & retVal)
		{
			double para = args.GetDouble(0);
			retVal.WriteDouble(::sin(para));
		}
		static void write(BufferRef<unsigned char> args, WritableBuffer & retVal)
		{
			printf_s("%s", args.GetString(0)->ToMultiByteString());
		}
		static void writeln(BufferRef<unsigned char> args, WritableBuffer & retVal)
		{
			printf_s("%s\n", args.GetString(0)->ToMultiByteString());
		}
		static void int2str(BufferRef<unsigned char> args, WritableBuffer & retVal)
		{
			int val = args.GetInt(0);
			retVal.WriteString(String(val));
		}
		static void double2str(BufferRef<unsigned char> args, WritableBuffer & retVal)
		{
			double val = args.GetDouble(0);
			retVal.WriteString(String(val));
		}
		static void parse_int(BufferRef<unsigned char> args, WritableBuffer & retVal)
		{
			retVal.WriteInt(StringToInt(*args.GetString(0)));
		}
		static void parse_double(BufferRef<unsigned char> args, WritableBuffer & retVal)
		{
			retVal.WriteDouble(StringToDouble(*args.GetString(0)));
		}
	public:
		SystemFunctionHandler()
		{
			externFuncs.Add(L"sin", sin);
			externFuncs.Add(L"write", write);
			externFuncs.Add(L"writeln", writeln);
			externFuncs.Add(L"int2str", int2str);
			externFuncs.Add(L"double2str", double2str);
			externFuncs.Add(L"parse_int", parse_int);
			externFuncs.Add(L"parse_double", parse_double);
		}
		bool HandleExternFunctionCall(	String functionName,
										BufferRef<unsigned char> arguments,
										WritableBuffer & retVal) override
		{
			ExternFunction handlerFunc;
			if (externFuncs.TryGetValue(functionName, handlerFunc))
			{
				handlerFunc(arguments, retVal);
				return true;
			}
			return false;
		}
	};

	Machine::Machine(int stackSize)
	{
		stack = new unsigned char[stackSize];
		AddExternFunctionHandler(new SystemFunctionHandler());
	}

	void Machine::Run(ProgramCode * code)
	{
		program = code;
		strStack.AddRange(code->StringBuffer);
		terminated = true;
		for (int i = 0; i < code->Functions.Count(); i++)
		{
			if (code->Functions[i]->Name == L"main")
			{
				auto mainFunc = code->Functions[i];
				curFunc = code->Functions[i].Ptr();
				eip = 0;
				terminated = false;
				break;
			}
		}
		esp = 0;
		Instruction initialInstr;
		initialInstr.IntOperand = -1;
		Instr_iPush(initialInstr);
		ebp = 0;
		while (!terminated)
		{
			auto & instr = curFunc->Instructions[eip];
			switch (instr.Operator)
			{
			case OpCode::cPush:
				Instr_cPush(instr);
				break;
			case OpCode::iPush:
				Instr_iPush(instr);
				break;
			case OpCode::dPush:
				Instr_dPush(instr);
				break;
			case OpCode::sPush:
				Instr_sPush(instr);
				break;
			case OpCode::Pop:
				Instr_Pop(instr);
				break;
			case OpCode::sPop:
				Instr_Pop(instr);
				break;
			case OpCode::PushEmpty:
				Instr_PushEmpty(instr);
				break;
			case OpCode::sAdd:
				Instr_sAdd(instr);
				break;
			case OpCode::iAdd:
				Instr_iAdd(instr);
				break;
			case OpCode::iSub:
				Instr_iSub(instr);
				break;
			case OpCode::iMul:
				Instr_iMul(instr);
				break;
			case OpCode::iDiv:
				Instr_iDiv(instr);
				break;
			case OpCode::Mod:
				Instr_Mod(instr);
				break;
			case OpCode::dAdd:
				Instr_dAdd(instr);
				break;
			case OpCode::dSub:
				Instr_dSub(instr);
				break;
			case OpCode::dMul:
				Instr_dMul(instr);
				break;
			case OpCode::dDiv:
				Instr_dDiv(instr);
				break;
			case OpCode::And:
				Instr_And(instr);
				break;
			case OpCode::Or:
				Instr_Or(instr);
				break;
			case OpCode::Xor:
				Instr_Xor(instr);
				break;
			case OpCode::BitAnd:
				Instr_BitAnd(instr);
				break;
			case OpCode::BitOr:
				Instr_BitOr(instr);
				break;
			case OpCode::Not:
				Instr_Not(instr);
				break;
			case OpCode::iNeg:
				Instr_iNeg(instr);
				break;
			case OpCode::dNeg:
				Instr_dNeg(instr);
				break;
			case OpCode::Inc:
				Instr_Inc(instr);
				break;
			case OpCode::Dec:
				Instr_Dec(instr);
				break;
			case OpCode::Rsh:
				Instr_Rsh(instr);
				break;
			case OpCode::Lsh:
				Instr_Lsh(instr);
				break;
			case OpCode::iEql:
				Instr_iEql(instr);
				break;
			case OpCode::iNeq:
				Instr_iNeq(instr);
				break;
			case OpCode::iGeq:
				Instr_iGeq(instr);
				break;
			case OpCode::iLeq:
				Instr_iLeq(instr);
				break;
			case OpCode::iLess:
				Instr_iLess(instr);
				break;
			case OpCode::iGreater:
				Instr_iGreater(instr);
				break;
			case OpCode::dEql:
				Instr_dEql(instr);
				break;
			case OpCode::dNeq:
				Instr_dNeq(instr);
				break;
			case OpCode::dGeq:
				Instr_dGeq(instr);
				break;
			case OpCode::dLeq:
				Instr_dLeq(instr);
				break;
			case OpCode::dLess:
				Instr_dLess(instr);
				break;
			case OpCode::dGreater:
				Instr_dGreater(instr);
				break;
			case OpCode::i2d:
				Instr_i2d(instr);
				break;
			case OpCode::d2i:
				Instr_d2i(instr);
				break;
			case OpCode::c2s:
				Instr_c2s(instr);
				break;
			case OpCode::iLoad:
				Instr_iLoad(instr);
				break;
			case OpCode::dLoad:
				Instr_dLoad(instr);
				break;
			case OpCode::cLoad:
				Instr_cLoad(instr);
				break;
			case OpCode::sLoad:
				Instr_sLoad(instr);
				break;
			case OpCode::LoadOffset:
				Instr_LoadOffset(instr);
				break;
			case OpCode::sLoadOffset:
				Instr_sLoadOffset(instr);
				break;
			case OpCode::iStore:
				Instr_iStore(instr);
				break;
			case OpCode::dStore:
				Instr_dStore(instr);
				break;
			case OpCode::cStore:
				Instr_cStore(instr);
				break;
			case OpCode::sStore:
				Instr_sStore(instr);
				break;
			case OpCode::StoreOffset:
				Instr_StoreOffset(instr);
				break;
			case OpCode::sStoreOffset:
				Instr_sStoreOffset(instr);
				break;
			case OpCode::Jump:
				Instr_Jump(instr);
				break;
			case OpCode::JumpTrue:
				Instr_JumpTrue(instr);
				break;
			case OpCode::JumpFalse:
				Instr_JumpFalse(instr);
				break;
			case OpCode::Call:
				Instr_Call(instr);
				break;
			case OpCode::Ret:
				Instr_Ret(instr);
				break;
			default:
				break;
			}
			eip ++;
		}
	}

	void Machine::Instr_cPush(Instruction & instr)
	{
		*(wchar_t*)(stack + esp) = (wchar_t)(instr.IntOperand);
		esp += sizeof(wchar_t);
	}
	void Machine::Instr_iPush(Instruction & instr)
	{
		PushInt(instr.IntOperand);
	}
	void Machine::Instr_dPush(Instruction & instr)
	{
		*(double *)(stack + esp) = instr.DoubleOperand;
		esp += sizeof(double);
	}
	void Machine::Instr_sPush(Instruction & instr)
	{
		String * str = new String(program->StringBuffer[instr.IntOperand]);
		*(String * *)(stack + esp) = str;
		esp += sizeof(String *);
	}
	void Machine::Instr_Pop(Instruction & instr)
	{
		esp -= instr.IntOperand;
	}
	void Machine::Instr_sPop(Instruction & instr)
	{
		String * strAddr = *(String **)(stack + esp - sizeof(String *));
		if(strAddr)
			delete strAddr;
		esp -= sizeof(String *);
	}
	void Machine::Instr_PushEmpty(Instruction & instr)
	{
		memset(stack + esp, 0, sizeof(char) * instr.IntOperand);
		esp += instr.IntOperand;
	}
	void Machine::Instr_sAdd(Instruction & instr)
	{
		esp -= sizeof(String *);
		String * strAddr1 = *(String **)(stack + esp);
		esp -= sizeof(String *);
		String * strAddr2 = *(String **)(stack + esp);

		String * str = new String(*strAddr2 + * strAddr1);
		if (strAddr1)
			delete strAddr1;
		if (strAddr2)
			delete strAddr2;
		*(String * *)(stack + esp) = str;
		esp += sizeof(String *);
	}
	void Machine::Instr_iAdd(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val1 + val2;
		esp += sizeof(int *);
	}
	void Machine::Instr_iSub(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 - val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_iMul(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val1 * val2;
		esp += sizeof(int *);
	}
	void Machine::Instr_iDiv(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 / val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_Mod(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 % val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_dAdd(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val1 + val2;
		esp += sizeof(double *);
	}
	void Machine::Instr_dSub(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 - val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_dMul(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val1 * val2;
		esp += sizeof(double *);
	}
	void Machine::Instr_dDiv(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 / val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_And(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val1 && val2;
		esp += sizeof(int *);
	}
	void Machine::Instr_Or(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val1 || val2;
		esp += sizeof(int *);
	}
	void Machine::Instr_Xor(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val1 ^ val2;
		esp += sizeof(int *);
	}
	void Machine::Instr_BitAnd(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val1 & val2;
		esp += sizeof(int *);
	}
	void Machine::Instr_BitOr(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val1 | val2;
		esp += sizeof(int *);
	}
	void Machine::Instr_Not(Instruction & instr)
	{
		*(int *)(stack + esp - sizeof(int)) = !(*(int *)(stack + esp - sizeof(int)));
	}
	void Machine::Instr_iNeg(Instruction & instr)
	{
		*(int *)(stack + esp - sizeof(int)) = -(*(int *)(stack + esp - sizeof(int)));
	}
	void Machine::Instr_dNeg(Instruction & instr)
	{
		*(double *)(stack + esp - sizeof(double)) = -(*(double *)(stack + esp - sizeof(double)));
	}
	void Machine::Instr_Inc(Instruction & instr)
	{
		(*(int *)(stack + esp - sizeof(int)))++;
	}
	void Machine::Instr_Dec(Instruction & instr)
	{
		(*(int *)(stack + esp - sizeof(int)))--;
	}
	void Machine::Instr_Rsh(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 >> val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_Lsh(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 << val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_iEql(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 == val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_iNeq(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 != val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_iGeq(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 >= val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_iLeq(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 <= val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_iLess(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 < val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_iGreater(Instruction & instr)
	{
		esp -= sizeof(int);
		int val1 = *(int *)(stack + esp);
		esp -= sizeof(int);
		int val2 = *(int *)(stack + esp);

		*(int *)(stack + esp) = val2 > val1;
		esp += sizeof(int *);
	}
	void Machine::Instr_dEql(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 == val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_dNeq(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 != val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_dGeq(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 >= val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_dLeq(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 <= val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_dLess(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 < val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_dGreater(Instruction & instr)
	{
		esp -= sizeof(double);
		double val1 = *(double *)(stack + esp);
		esp -= sizeof(double);
		double val2 = *(double *)(stack + esp);

		*(double *)(stack + esp) = val2 > val1;
		esp += sizeof(double *);
	}
	void Machine::Instr_i2d(Instruction & instr)
	{
		esp -= sizeof(int);
		int val = *(int *)(stack + esp);
		double dVal = (double)val;
		*(double *)(stack + esp) = dVal;
		esp += sizeof(double);
	}
	void Machine::Instr_d2i(Instruction & instr)
	{
		esp -= sizeof(double);
		double val = *(double *)(stack + esp);
		int ival = (int)val;
		*(int *)(stack + esp) = ival;
		esp += sizeof(int);
	}
	void Machine::Instr_c2s(Instruction & instr)
	{
		esp -= sizeof(wchar_t);
		wchar_t ch = *(wchar_t *)(stack + esp);
		String *str = new String(ch);
		*(String * *)(stack + esp) = str;
		esp += sizeof(String *);
	}
	void Machine::Instr_iLoad(Instruction & instr)
	{
		int val = *(int *)(stack + ebp + instr.IntOperand);
		*(int *)(stack + esp) = val;
		esp += sizeof(int);
	}
	void Machine::Instr_dLoad(Instruction & instr)
	{
		double val = *(double *)(stack + ebp + instr.IntOperand);
		*(double *)(stack + esp) = val;
		esp += sizeof(double);
	}
	void Machine::Instr_cLoad(Instruction & instr)
	{
		wchar_t val = *(wchar_t *)(stack + ebp + instr.IntOperand);
		*(wchar_t *)(stack + esp) = val;
		esp += sizeof(wchar_t);
	}
	void Machine::Instr_sLoad(Instruction & instr)
	{
		String * str = *(String * *)(stack + ebp + instr.IntOperand);
		String * strNew = new String(*str);
		*(String * *)(stack + esp) = strNew;
		esp += sizeof(String *);
	}
	void Machine::Instr_LoadOffset(Instruction & instr)
	{
		esp -= sizeof(int);
		int offset = *(int *)(stack + esp);
		memcpy(stack + esp, stack + ebp + offset, instr.IntOperand);
		esp += instr.IntOperand;
	}
	void Machine::Instr_sLoadOffset(Instruction & instr)
	{
		esp -= sizeof(int);
		int offset = *(int *)(stack + esp);
		for (int i = 0; i < instr.IntOperand / (int)sizeof(String *); i++)
		{
			String * str = *(String * *)(stack + ebp + offset + i * sizeof(String *));
			String * newStr = new String(*str);
			*(String * *)(stack + esp) = newStr;
			esp += sizeof(String *);
		}
	}
	void Machine::Instr_iStore(Instruction & instr)
	{
		esp -= sizeof(int);
		int val = *(int *)(stack + esp);
		*(int *)(stack + ebp + instr.IntOperand) = val;
	}
	void Machine::Instr_dStore(Instruction & instr)
	{
		esp -= sizeof(double);
		double val = *(double *)(stack + esp);
		*(double *)(stack + ebp + instr.IntOperand) = val;
	}
	void Machine::Instr_cStore(Instruction & instr)
	{
		esp -= sizeof(wchar_t);
		wchar_t val = *(wchar_t *)(stack + esp);
		*(wchar_t *)(stack + ebp + instr.IntOperand) = val;
	}
	void Machine::Instr_sStore(Instruction & instr)
	{
		esp -= sizeof(String *);
		String * strAddr1 = *(String **)(stack + esp);
		if (*(String * *)(stack + ebp + instr.IntOperand))
			delete *(String * *)(stack + ebp + instr.IntOperand);
		*(String * *)(stack + ebp + instr.IntOperand) = strAddr1;
	}
	void Machine::Instr_StoreOffset(Instruction & instr)
	{
		esp -= sizeof(int);
		int offset = *(int *)(stack + esp);
		int sizeInBytes = instr.IntOperand;
		esp -= sizeInBytes;
		memcpy(stack + ebp + offset, stack + esp, sizeInBytes);
	}
	void Machine::Instr_sStoreOffset(Instruction & instr)
	{
		esp -= sizeof(int);
		int offset = *(int *)(stack + esp);
		int sizeInBytes = instr.IntOperand;
		esp -= sizeInBytes;

		for (int i = 0; i < instr.IntOperand/(int)sizeof(String*); i++)
		{
			if (*(String * *)(stack + ebp + offset + i*sizeof(String*)))
				delete *(String * *)(stack + ebp + offset + i * sizeof(String *));
		}
		memcpy(stack + ebp + offset, stack + esp, sizeInBytes);
	}
	void Machine::Instr_Jump(Instruction & instr)
	{
		eip = instr.IntOperand;
		eip--;
	}
	void Machine::Instr_JumpTrue(Instruction & instr)
	{
		esp -= sizeof(int);
		int val = *(int *)(stack + esp);
		if (val)
		{
			eip = instr.IntOperand;
			eip--;
		}
	}
	void Machine::Instr_JumpFalse(Instruction & instr)
	{
		esp -= sizeof(int);
		int val = *(int *)(stack + esp);
		if (!val)
		{
			eip = instr.IntOperand;
			eip--;
		}
	}
	void Machine::Instr_Call(Instruction & instr)
	{
		//function index
		esp -= sizeof(int);
		int funcIndex = *(int *)(stack + esp);
		auto newFunc = program->Functions[funcIndex].Ptr();
		if (newFunc->External)
		{
			List<unsigned char> argBuffer;
			argBuffer.AddRange(stack + esp - newFunc->ArgumentSize, newFunc->ArgumentSize);
			esp -= newFunc->ArgumentSize;
			WritableBuffer retBuffer(stack, &esp);
			bool found = false;
			bool externException = false;
			try
			{
				for (auto & handler : externHandlers)
				{
					if (handler->HandleExternFunctionCall(newFunc->Name,
						BufferRef<unsigned char>(argBuffer.Buffer(), argBuffer.Count()),
						retBuffer))
					{
						found = true;
						break;
					}
				}
			}
			catch (RuntimeException)
			{
				externException = true;
			}
			for (auto & strOffset : newFunc->StrVarOffsets)
			{
				auto strPtr = *(String**)(argBuffer.Buffer() + argBuffer.Count() + strOffset + 8);
				if (strPtr)
					delete strPtr;
			}
			if (!found)
			{
				throw RuntimeException(String(L"External function \"") + newFunc->Name + L"\" not found.");
			}
			if (externException)
				throw RuntimeException(String(L"Runtime exception in external function \"" + newFunc->Name + L"\"."));
		}
		else
		{
			//save and update curFunc
			*(FunctionCode * *)(stack + esp) = curFunc;
			esp += sizeof(FunctionCode *);
			curFunc = newFunc;

			//save and update eip
			*(int *)(stack + esp) = eip;
			esp += sizeof(int);
			eip = -1;

			//save and update ebp
			*(int *)(stack + esp) = ebp;
			ebp = esp;
			esp += sizeof(int);
		}
	}
	void Machine::Instr_Ret(Instruction & instr)
	{
		int paramSize = instr.Operand[0];
		int retSize = instr.Operand[1];
		//save return value
		char * retBuffer = 0;
		if (retSize)
		{
			retBuffer = new char[retSize];
			esp -= retSize;
			memcpy(retBuffer, stack + esp, retSize);
		}
		//delete string
		for (int i = 0; i < curFunc->StrVarOffsets.Count(); i++)
		{
			if (*(String * *)(stack + ebp + curFunc->StrVarOffsets[i]))
				delete *(String * *)(stack + ebp + curFunc->StrVarOffsets[i]);
		}
		//set esp, ebp, eip
		esp = ebp;
		ebp = *(int *)(stack + ebp);
		if (ebp == -1)
			terminated = true;
		else
		{
			esp -= sizeof(int);
			eip = *(int *)(stack + esp);
			esp -= sizeof(FunctionCode *);
			curFunc = *(FunctionCode * *)(stack + esp);
			esp -= paramSize;
		}

		//push return value
		if (retSize)
		{
			memcpy(stack + esp, retBuffer, retSize);
			esp += retSize;
			delete[] retBuffer;
		}
	}
}